﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace WebClass
{
    public class ExistingLabelingResult
    {
        public string Query { get; set; }
        public int Rank { get; set; }
        public bool IsLabeled { get; set; }
        public ExistingLabelingResult()
        {
            IsLabeled = false;
        }
    }
    public class Experiments
    {
        public int NewsID { get; set; }
        public Guid ExpID { get; set; }
        public List<string> Queries { get; set; }
        public Experiments()
        {
            NewsID = -1;
            Queries = new List<string>();
        }
    }
    public class PrecisionRecallCoverage
    {
        public string ExperimentID { get; set; }
        public string ExperimentName { get; set; }
        public PrecisionInput PrecisionInput { get; set; }
        public PrecisionOutput PrecisionOutput { get; set; }
        public RecallInput RecallInput { get; set; }
        public RecallOutput RecallOutput { get; set; }
        public CoverageInput CoverageInput { get; set; }
        public CoverageOutput CoverageOutput { get; set; }
        public PrecisionRecallCoverage()
        {
            PrecisionInput = new PrecisionInput();
            PrecisionOutput = new PrecisionOutput();
            RecallInput = new RecallInput();
            RecallOutput = new RecallOutput();
            CoverageInput = new CoverageInput();
            CoverageOutput = new CoverageOutput();
        }
    }
    public class QueryControlData
    {
        public string Query { get; set; }
        public int Position { get; set; }
        public int NewsID { get; set; }
    }
    public class ExperimentsQueries
    {
        public tb_new News2 { get; set; }
        public int NewsID { get; set; }
        public int TaskID { get; set; }
        public int UserID { get; set; }
        public List<QueryControlData> ListQueryControlData { get; set; }
        ResearchDBDataContext researchDB;
        public ExperimentsQueries()
        {
            researchDB = new ResearchDBDataContext();
            ListQueryControlData = new  List<QueryControlData>();
        }
        public string GetTaskName(int taskID)
        {
            var res = from t in researchDB.tb_tasks where t.ID == taskID select t;
            if (res.Count() > 0)
            {
                return res.First().name;
            }
            return "";
        }
        private bool IsQueryAllComplete(int experimentID)
        {
            var res = from e in researchDB.tb_experiments
                      from q in e.tb_experimentsQueries
                      where q.tb_experiment.ID == experimentID && q.rank == -1
                      select q;
            if (res.Count() == 0)
            {
                return true;
            }
            return false;
        }
        public void GetExperimentsQueries(int _userID, int _taskID, out int existExpeNum,out int allExpNum)
        {
            TaskID = _taskID;
            UserID = _userID;
            researchDB = new ResearchDBDataContext();

            var allNewsResult = from n in researchDB.tb_experiments where
                                 n.userID == UserID && n.taskID == TaskID group n by n.newsID into g select g;
            allExpNum = allNewsResult.Count();
            
            var notCompleteNewsResult = from n in researchDB.tb_experiments where
                                n.userID == UserID && n.taskID == TaskID && n.isComplete == false
                                group n by n.newsID into g select g;
            existExpeNum = notCompleteNewsResult.Count();
            if(existExpeNum > 0)
            {
                NewsID = (int)notCompleteNewsResult.First().Key.Value;
                News2 = (from n in researchDB.tb_news where n.ID == NewsID select n).First();
                var queryResult = (from e in researchDB.tb_experiments
                                   from q in e.tb_experimentsQueries
                                   where e.userID == UserID && e.taskID == TaskID && e.newsID == NewsID && q.rank == -1
                                   select new
                                  {
                                      query = q.query,
                                      position = q.position
                                  }).Distinct();
                foreach (var item in queryResult)
                {
                    QueryControlData queryControlData = new QueryControlData();
                    queryControlData.Query = item.query;
                    if (item.position != null)
                    {
                        queryControlData.Position = (int)item.position;
                    }
                    else
                    {
                        queryControlData.Position = -2;
                    }
                    queryControlData.NewsID = NewsID;
                    ListQueryControlData.Add(queryControlData);
                }
            }
        }

        public void SaveEvaluateQuery(List<int> listEvaluate)
        {
            var experimentsResult = from e in researchDB.tb_experiments
                                    where e.newsID == NewsID && e.taskID == TaskID && e.userID == UserID && e.isComplete == false
                                    select e;
            foreach (var item in experimentsResult)
            {
                foreach (tb_experimentsQuery query in item.tb_experimentsQueries)
                {
                    string strQuery = query.query;
                    int index = ListQueryControlData.FindIndex(delegate(QueryControlData s)
                    {
                        if (s.Query == strQuery)
                        {
                            return true;
                        }
                        return false;
                    });
                    if (index != -1)
                    {
                        query.rank = listEvaluate.ElementAt(index);
                    }
                }
                researchDB.SubmitChanges();
                if (IsQueryAllComplete(item.ID) == true)
                {
                    item.isComplete = true;
                }
            }
            researchDB.SubmitChanges();
            int index2 = 0;
            foreach (QueryControlData queryControlData in ListQueryControlData)
            {
                int rank = listEvaluate.ElementAt(index2);
                if(rank == 0 || rank == 1)  
                {
                    tb_standardQuery tb_s = new tb_standardQuery
                    {
                        newsID = NewsID,
                        query = queryControlData.Query,
                        taskID = TaskID
                    };
                    researchDB.tb_standardQueries.InsertOnSubmit(tb_s);
                }
                ++index2;
            }
            researchDB.SubmitChanges();
        }
        //if "append" is conflict with "radio", then "append" didn't be added. "listEvaluate" is used to judge if there is confict.
        public void SaveAppendQuery(string[] arrayAppendQuery,List<int> listEvaluate)
        {
            foreach (string s in arrayAppendQuery)
            {
                if(ListQueryControlData.FindIndex(delegate(QueryControlData ss)
                {
                    if (News.IsSynonym(ss.Query, s))
                    {
                        return true;
                    }
                    return false;
                }) == -1)
                {
                    tb_standardQuery tb_s = new tb_standardQuery
                    {
                        newsID = NewsID,
                        query = s,
                        taskID = TaskID
                    };
                    researchDB.tb_standardQueries.InsertOnSubmit(tb_s);
                }
                researchDB.SubmitChanges();
            }
        }
        public void SubmitQueries()
        {
            researchDB.SubmitChanges();
        }
        public List<PrecisionRecallCoverage> GetDataAndCalcuPrecisionRecall(int taskID)
        {
            List<PrecisionRecallCoverage> listExpPreAndRe = new List<PrecisionRecallCoverage>();
            var allResullt = from e in researchDB.tb_experiments
                             from q in e.tb_experimentsQueries
                             where e.taskID == taskID
                             group q by e.expID into g
                             select g;
            int tpAndFnCount = (from q in researchDB.tb_standardQueries
                                where q.taskID == taskID
                                select q).Count();
            foreach (var item in allResullt)
            {
                List<int> listQueryRank = new List<int>();
                List<int> listQueryPosition = new List<int>();
                PrecisionRecallCoverage precisionRecallCoverage = new PrecisionRecallCoverage();
                precisionRecallCoverage.ExperimentID = item.Key;
                precisionRecallCoverage.ExperimentName = (from exp in researchDB.tb_exps where exp.ID == precisionRecallCoverage.ExperimentID
                                             select exp.name).First();
                foreach (var query in item)
                {
                    listQueryRank.Add((int)query.rank);
                    listQueryPosition.Add((int)query.position);
                }
                listExpPreAndRe.Add(precisionRecallCoverage);
            }
            return listExpPreAndRe;
        }
        //Calculate Precision.
        public void Precision(List<int> listQueryRank,PrecisionRecallCoverage _data)
        {
            int tp = 0;
            int fp = 0;
            GetTpFp(listQueryRank, out tp, out fp);
            _data.PrecisionInput.FP = fp;
            _data.PrecisionInput.TP = tp;
           CalculateMeasuredValue calcuPrecision = new CalculatePrecision();
           _data.PrecisionOutput = (PrecisionOutput)(calcuPrecision.Calculate((CalculateInput)(_data.PrecisionInput)));
        }
        //Calculate Recall.
        public void Recall(List<int> listQueryRank, int goldenSetCount,PrecisionRecallCoverage _data)
        {
            int tp = 0;
            int fp = 0;
            GetTpFp(listQueryRank, out tp, out fp);
            int fn = goldenSetCount - tp;
            if (tp > goldenSetCount)
            {
                throw new ArgumentException("tp in listQueryRank should smaller than goldenSetCount");
            }
            _data.RecallInput.TP = tp;
            _data.RecallInput.FN = fn;
            CalculateMeasuredValue calcuRecall = new CalculateRecall();
            _data.RecallOutput = (RecallOutput)(calcuRecall.Calculate((CalculateInput)_data.RecallInput));
        }
        //Calculate Covarage.
        public void Coverage(List<int> listQueryPosition, PrecisionRecallCoverage _data)
        {
            int hitNum = 0;
            int total = listQueryPosition.Count;
            foreach (int position in listQueryPosition)
            {
                if (position >= 0)
                {
                    ++hitNum;
                }
            }
            _data.CoverageInput.HitTargetCount = hitNum;
            _data.CoverageInput.Total = total;
            CalculateMeasuredValue calcuCoverage = new CalculateCoverage();
            _data.CoverageOutput = (CoverageOutput)(calcuCoverage.Calculate((CalculateInput)_data.CoverageInput));
        }
        private void GetTpFp(List<int> listQueryRank, out int _tp, out int _fp)
        {
            if (listQueryRank == null)
            {
                throw new ArgumentException("listQueryRank should not empty");
            }
            int tp = 0;
            int fp = 0;
            foreach (int queryRank in listQueryRank)
            {
                if (queryRank == 0 || queryRank == 1)
                {
                    ++tp;
                }
                else if (queryRank == 2)
                {
                    ++fp;
                }
            }
            _tp = tp;
            _fp = fp;
        }
        public int NewsCompleteCount(int taskID)
        {
            var result = (from e in researchDB.tb_experiments
                          where e.taskID == taskID && e.isComplete == true
                          group e by e.newsID into g
                          select g).Count();
            return result;
        }
        public int NewsTotalCount(int taskID)
        {
            var result = (from e in researchDB.tb_experiments
                          where e.taskID == taskID
                          group e by e.newsID into g
                          select g).Count();
            return result;
        }
        public List<ExistingLabelingResult> GetNewsQuery(int taskID, int newsID)
        {
            var result = (from q in researchDB.tb_experimentsQueries
                          where
                              (from e in researchDB.tb_experiments
                               where e.taskID == taskID && e.newsID == newsID
                               select e.ID).Contains((int)q.experimentsID)
                          select new
                              {
                                  Query = q.query,
                                  Rank = q.rank
                              }).Distinct();
            List<ExistingLabelingResult> listExisting = new List<ExistingLabelingResult>();
            foreach (var item in result)
            {
                ExistingLabelingResult e = new ExistingLabelingResult
                {
                    Query = item.Query,
                    Rank = (int)item.Rank,
                    IsLabeled = false
                };
                listExisting.Add(e);
            }

            var result2 = from s in researchDB.tb_standardQueries
                          where s.taskID == taskID && s.newsID == newsID
                          select s;
            foreach (var item in result2)
            {
                if (listExisting.FindIndex(delegate(ExistingLabelingResult eLabel)
                {
                    if (eLabel.Query == item.query)
                    {
                        return true;
                    }
                    return false;
                }) == -1)
                {
                    ExistingLabelingResult e = new ExistingLabelingResult
                    {
                        Query = item.query,
                        Rank = 0,
                        IsLabeled = false
                    };
                    listExisting.Add(e);
                }
            }
            return listExisting; 
        }
    }
}
